﻿/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using moose.irc;

namespace MooseIRC.Client.Server {

    /// <summary>
    /// Base Server Class
    /// </summary>
    internal abstract class Server : object, IDisposable {

        #region [Local Attributes]

        /// <summary>
        /// Locally Bound Endpoint
        /// </summary>
        protected IPEndPoint m_local_endpoint;

        /// <summary>
        /// Listening Socket
        /// </summary>
        protected Socket m_socket_listener;

        #endregion

        #region [Public Properties]

        /// <summary>
        /// Gets Port accepting connections on
        /// </summary>
        public int Port {
            get {
                if (m_local_endpoint != null) {
                    return m_local_endpoint.Port;
                }
                else {
                    return -1;
                }
            }
        }

        #endregion

        #region [Construction]

        /// <summary>
        /// Initialize Server
        /// </summary>
        public Server() : base() {
            initialize_server();

            return;
        }

        #endregion

        #region [Helper Methods]

        /// <summary>
        /// Initialize the server
        /// </summary>
        private void initialize_server() {
            int port;
            try {
                if (int.TryParse(Settings.MasterSettings["server"]["port"], out port)) {
                    m_socket_listener = create_socket();
                    while (!m_socket_listener.IsBound) {
                        m_local_endpoint = new IPEndPoint(IPAddress.Loopback, port);
                        try {
                            m_socket_listener.Bind(m_local_endpoint);
                        } catch (Exception) {
                            Console.WriteLine("Port: {0} is in use...", port);
                            port++;
                        }
                    }
                    Console.WriteLine("Bound to: {0}", port);
                    m_socket_listener.Listen(4);
                    m_socket_listener.BeginAccept( onAcceptComplete, null ); 
                }
                else {
                    Console.WriteLine("Port must be numeric");
                }
            } catch (Exception) {
                Console.WriteLine("port must be specified in the configuration section");
            }
            return;
        }

        /// <summary>
        /// Create a socket
        /// </summary>
        /// <returns>New Socket</returns>
        private Socket create_socket() {
            return new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        #endregion

        #region [Async Socket Handlers]

        /// <summary>
        /// Fires upon successful connection (Must be overriden)
        /// </summary>
        /// <param name="result">Async Result</param>
        protected abstract void onAcceptComplete(IAsyncResult result);

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Cleanup Server
        /// </summary>
        public virtual void Dispose() {
            if (m_socket_listener != null) {
                m_socket_listener.Close(5000);
                m_socket_listener = null;
            }
            return;
        }

        #endregion
    }
}
